package com.zxjbyte.yiyi.framework.web.xss;

import com.zxjbyte.yiyi.framework.common.util.ServletXUtil;
import com.zxjbyte.yiyi.framework.web.config.XssProperties;
import com.zxjbyte.yiyi.framework.web.config.YiyiWebProperties;
import com.zxjbyte.yiyi.framework.web.xss.clean.IXssCleaner;
import com.zxjbyte.yiyi.framework.web.xss.wrapper.YiyiXssHttpServletRequestWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 *  XSS 防御过滤器
 *
 * @Author zhangxingjia
 * @Date 2025/11/3 22:38
 * @Version: 1.0
 */
@Slf4j
@RequiredArgsConstructor
public class XssFilter extends OncePerRequestFilter {

    private final XssProperties xssProperties;
    private final YiyiWebProperties yiyiWebProperties;
    private final IXssCleaner xssCleaner;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 只在 shouldNotFilter() 返回 false 时才会执行这里
        if (xssProperties.getLogDetails()) {
            log.debug("[XssFilter] Apply XSS cleaning for URI: {}", request.getRequestURI());
        }
        filterChain.doFilter(new YiyiXssHttpServletRequestWrapper(request, xssCleaner), response);
    }

    /**
     * 返回 true 表示跳过过滤器
     */
    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        if (!xssProperties.getEnabled()) {
            if (log.isTraceEnabled()) {
                log.trace("[XssFilter] XSS cleaning disabled globally");
            }
            return true;
        }

        String path = ServletXUtil.getRequestPath(request);
        // 使用全局排除路径
        List<String> excludes = yiyiWebProperties.getExcludePaths();
        if (ServletXUtil.matchesAnyPattern(path, excludes)) {
            if (log.isTraceEnabled()) {
                log.trace("[XssFilter] Skip XSS filter for excluded path: {}", path);
            }
            return true;
        }

        // 判断是否在排除路径中
        return ServletXUtil.matchesAnyPattern(path, xssProperties.getExcludePaths());
    }

}
